篇首语:本文由编程笔记#小编为大家整理,主要介绍了jQuery异步框架探究1:jQuery._Deferred方法相关的知识,希望对你有一定的参考价值。
与异步框架相关的方法定义于jQuery类的静态方法中。只有三个方法,但是功能和应用及其强大!本篇详细讲解第一个方法jQuery._Deferred()。
_Deferred: function()
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred =
// done( f1, f2, ...)
done: function()
if ( !cancelled )
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired )
_fired = fired;
fired = 0;
for ( i = 0, length = args.length; i
type = jQuery.type( elem );
if ( type === "array" )
deferred.done.apply( deferred, elem );
else if ( type === "function" )
callbacks.push( elem );
if ( _fired )
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
return this;
,
// resolve with given context and args
resolveWith: function( context, args )
if ( !cancelled && !fired && !firing )
// make sure args are available (#8421)
args = args || [];
firing = 1;
try
while( callbacks[ 0 ] )
callbacks.shift().apply( context, args );
finally
fired = [ context, args ];
firing = 0;
return this;
,
// resolve with this as context and given arguments
resolve: function()
deferred.resolveWith( this, arguments );
return this;
,
// Has this deferred been resolved?
isResolved: function()
return !!( firing || fired );
,
// Cancel
cancel: function()
cancelled = 1;
callbacks = [];
return this;
;
return deferred;
,
这是jQuery异步框架最基础的一个函数,真正对外暴露的Deferred函数依赖该函数的实现,从其名字可以看出,jQuery的设计者并不想使用者直接调用该方法,虽然这个方法已经很灵活已经可以应用到很多场景了,而且Javascript语言也没有语言层面上的机制阻止用户真的调用该方法。
分析其内部实现可以发现该函数设计为在被调用时并不需要传入任何参数,而是直接调用后得到一个异步对象:var deferred = jQuery._Deferred()。重点是这个返回的异步对象,这个对象有五个方法:done、resolveWith、resolve、isResolved、cancel,每个方法都值得深入分析。当然_Deferred函数里面还有四个变量:callbacks、fired、firing、cancelled,这四个变量也值得深入分析。
if ( fired )
_fired = fired;
fired = 0;
// ......
if ( _fired )
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
除了前面两种操作外还有一种特殊操作:上弹-->开枪-->再上弹开枪(先调用done方法再调用resolveWith方法后再调用done方法),这个时候done方法装上新弹(传入新的函数参数push到回调函数数组)后可重复开枪(继续内部调用resolveWith方法),如果不换上新弹(不传入新的函数参数)就不能重复开枪(原回调函数数组经过resolveWith方法调用一次后已清空,它不可重复使用),这个操作时序完美的模拟手枪空仓挂机复位射击功能(子弹打光时阻止套筒回位,更换弹夹后可快速推弹入膛)!
这行代码"fired = 0;"的作用非常重要,正因为有这行代码才可以在done方法调用resolveWith方法重复开枪时生效(因为resolveWith方法内的第二个判断条件"if ( !cancelled && !fired && !firing )",我们前面说过fired变量表示枪套,怎么理解呢?关于枪套变量fired也需要重点解释,参见下面详细解释fired的部分。
我们再来看一个扩展的操作:jQuery._Deferred().done(f1,f2).resolveWith(context1, args1).done(f3).done([f4]).done(f5,[f6,f7]),说明空仓挂机复位射击的确是可重复的!这个世界上应该没有哪位枪械师会设计不能重复使用或只能重复使用一次的手枪吧?
关于这两个方法总结一下针对同一把枪的使用方法:
jQuery._Deferred().done(f1,f2).resolveWith(context1, args1)--先上弹后造枪,击发一次。
jQuery._Deferred().resolveWith(context1, args1).done(f1,f2)--先造枪后上弹,击发一次。
jQuery._Deferred().done(f1,f2).resolveWith(context1, args1).done(f3,f4).done([f5,f6],f7)--先上弹后造枪射击一次,再空仓挂机复位射击两次(可重复更多次射击)。
关于这两个方法即使做了总结之后也并没有完,注意前面的一个提示性描述:针对同一把枪,我们已经知道同一把枪可以重复使用不同的子弹,但是如果想针对不同的枪使用相同的子弹呢?这个需求是合理的--成员国众多的北约内部,标准9mm巴拉姆弹可不是只能应用于沙漠之鹰。
"针对不同的枪"说明需要调用resolveWith方法至少两次,第一次调用resolveWith方法传入的参数(context1, args1)代表第一把枪,第二次传入的参数(context2, args2)代表第二把枪,我们看看会发生什么情况:"jQuery._Deferred().done(f1,f2).resolveWith(context1, args1).resolveWith(context2,args2);"很遗憾,这个调用会歇菜!还是因为枪套变量fired的原因。变通一下呢:"jQuery._Deferred().done(f1,f2).resolveWith(context1, args1).done(f3).resolveWith(context2, args2)",还是不行!同样因为枪套变量fired的原因,resolveWith方法能且仅能调用一次,它不像done一样可以链式调用多次。
除了因为枪套变量fired的原因外,即使排除这个原因,"不同的枪使用相同的子弹"也是不能实现的,枪对子弹是一对多的关系,子弹对枪却是一对一的关系,即回调函数数组中的每一颗子弹被一只手枪击发后并不能被另一只枪再次击发,真正合理的需求描述是"不同型号的枪支应该可以使用相同规格的子弹"。
所以结论是--jQuery._Deferred()不能针对相同的子弹使用不同的手枪,它每次上弹后就认为只能匹配给第一次传入的手枪(或者说第一次造枪后就只能使用这种型号的这只手枪),如果要使用不同的手枪怎么办呢?--多次调用jQuery._Deferred()方法即可。